

#include <net/if_arp.h>
#include <netpacket/packet.h>
#include <sys/ioctl.h>
#include <netinet/in.h>

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <netinet/in.h>
#include <string.h>
#include <signal.h>
#include <time.h>
#include <syslog.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/socket.h>

#include <linux/if.h>           /* for IFNAMSIZ and co... */
#include <linux/wireless.h>

#include "rtdot1x.h"
#include "eloop.h"
#include "ieee802_1x.h"
#include "eapol_sm.h"
#include "ap.h"
#include "sta_info.h"
#include "radius_client.h"
#include "config.h"

//#define RT2860AP_SYSTEM_PATH   "/etc/Wireless/RT2860AP/RT2860AP.dat"


struct hapd_interfaces
{
    int count;
    rtapd **rtapd;
};

u32    RTDebugLevel = RT_DEBUG_ERROR;

/*
    ========================================================================

    Routine Description:
        Compare two memory block

    Arguments:
        Adapter                     Pointer to our adapter

    Return Value:
        0:          memory is equal
        1:          pSrc1 memory is larger
        2:          pSrc2 memory is larger

    Note:

    ========================================================================
*/
u16 RTMPCompareMemory(void *pSrc1,void *pSrc2, u16 Length)
{
    char *pMem1;
    char *pMem2;
    u16 Index = 0;

    pMem1 = (char*) pSrc1;
    pMem2 = (char*) pSrc2;

    for (Index = 0; Index < Length; Index++)
    {
        if (pMem1[Index] > pMem2[Index])
            return (1);
        else if (pMem1[Index] < pMem2[Index])
            return (2);
    }

    // Equal
    return (0);
}

int RT_ioctl(
    int             sid,
    int             param,
    char            *data,
    int             data_len,
    char            *prefix_name,
    unsigned char   apidx,
    int             flags)
{
    //char          name[12];
    int             ret = 1;
    struct iwreq    wrq;

    //sprintf(name, "ra%d", apidx);
    //name[3] = '\0';

    //strcpy(wrq.ifr_name, name);
    sprintf(wrq.ifr_name, "%s%d", prefix_name, apidx);

    wrq.u.data.flags = flags;
    wrq.u.data.length = data_len;
    wrq.u.data.pointer = (caddr_t) data;

    ret = ioctl(sid, param, &wrq);

    return ret;
}

void dot1x_set_IdleTimeoutAction(
    rtapd *rtapd,
    struct sta_info *sta,
    u32     idle_timeout)
{
    DOT1X_IDLE_TIMEOUT dot1x_idle_time;

    memset(&dot1x_idle_time, 0, sizeof(DOT1X_IDLE_TIMEOUT));

    memcpy(dot1x_idle_time.StaAddr, sta->addr, MAC_ADDR_LEN);

    dot1x_idle_time.idle_timeout =
        ((idle_timeout < DEFAULT_IDLE_INTERVAL) ? DEFAULT_IDLE_INTERVAL : idle_timeout);

    if (RT_ioctl(rtapd->ioctl_sock,
                 RT_PRIV_IOCTL,
                 (char *)&dot1x_idle_time,
                 sizeof(DOT1X_IDLE_TIMEOUT),
                 rtapd->prefix_wlan_name, sta->ApIdx,
                 RT_OID_802_DOT1X_IDLE_TIMEOUT))
    {
        DBGPRINT(RT_DEBUG_ERROR,"Failed to RT_OID_802_DOT1X_IDLE_TIMEOUT\n");
        return;
    }

}

static void Handle_reload_config(
    rtapd   *rtapd)
{
    struct rtapd_config *newconf;
#if MULTIPLE_RADIUS
    int i;
#endif // MULTIPLE_RADIUS //

    DBGPRINT(RT_DEBUG_TRACE, "Reloading configuration\n");

    /* create new config */
    newconf = Config_read(rtapd->ioctl_sock, rtapd->prefix_wlan_name);
    if (newconf == NULL)
    {
        DBGPRINT(RT_DEBUG_ERROR, "Failed to read new configuration file - continuing with old.\n");
        return;
    }

    /* TODO: update dynamic data based on changed configuration
     * items (e.g., open/close sockets, remove stations added to
     * deny list, etc.) */
    Radius_client_flush(rtapd);
    Config_free(rtapd->conf);
    rtapd->conf = newconf;
    Apd_free_stas(rtapd);

    /* when reStartAP, no need to reallocate sock
    for (i = 0; i < rtapd->conf->SsidNum; i++)
    {
        if (rtapd->sock[i] >= 0)
            close(rtapd->sock[i]);

        rtapd->sock[i] = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
        if (rtapd->sock[i] < 0)
        {
            perror("socket[PF_PACKET,SOCK_RAW]");
            return;
        }
    }*/

#if MULTIPLE_RADIUS
    for (i = 0; i < MAX_MBSSID_NUM; i++)
        rtapd->radius->mbss_auth_serv_sock[i] = -1;
#else
    rtapd->radius->auth_serv_sock = -1;
#endif

    if (Radius_client_init(rtapd))
    {
        DBGPRINT(RT_DEBUG_ERROR,"RADIUS client initialization failed.\n");
        return;
    }
#if MULTIPLE_RADIUS
    for (i = 0; i < rtapd->conf->SsidNum; i++)
        DBGPRINT(RT_DEBUG_TRACE, "auth_serv_sock[%d] = %d\n", i, rtapd->radius->mbss_auth_serv_sock[i]);
#else
    DBGPRINT(RT_DEBUG_TRACE,"rtapd->radius->auth_serv_sock = %d\n",rtapd->radius->auth_serv_sock);
#endif

}

static void Handle_read(int sock, void *eloop_ctx, void *sock_ctx)
{
    rtapd *rtapd = eloop_ctx;
    int len;
    unsigned char buf[3000];
    u8 *sa, *da, *pos, *pos_vlan, apidx=0, isVlanTag=0;
    u16 ethertype,i;
    priv_rec *rec;
    size_t left;
    u8  RalinkIe[9] = {221, 7, 0x00, 0x0c, 0x43, 0x00, 0x00, 0x00, 0x00};

    len = recv(sock, buf, sizeof(buf), 0);
    if (len < 0)
    {
        perror("recv");
        Handle_term(15,eloop_ctx,sock_ctx);
        return;
    }

    rec = (priv_rec*)buf;
    left = len -sizeof(*rec)+1;
    if (left <= 0)
    {
        DBGPRINT(RT_DEBUG_ERROR," too short recv\n");
        return;
    }

    sa = rec->saddr;
    da = rec->daddr;
    ethertype = rec->ethtype[0] << 8;
    ethertype |= rec->ethtype[1];

#ifdef ETH_P_VLAN
    if(ethertype == ETH_P_VLAN)
    {
        pos_vlan = rec->xframe;

        if(left >= 4)
        {
            ethertype = *(pos_vlan+2) << 8;
            ethertype |= *(pos_vlan+3);
        }

        if((ethertype == ETH_P_PRE_AUTH) || (ethertype == ETH_P_PAE))
        {
            isVlanTag = 1;
            DBGPRINT(RT_DEBUG_TRACE,"Recv vlan tag for 802.1x. (%02x %02x)\n", *(pos_vlan), *(pos_vlan+1));
        }
    }
#endif

    if ((ethertype == ETH_P_PRE_AUTH) || (ethertype == ETH_P_PAE))
    {
        // search this packet is coming from which interface
        for (i = 0; i < rtapd->conf->SsidNum; i++)
        {
            if (memcmp(da, rtapd->own_addr[i], 6) == 0)
            {
                apidx = i;
                break;
            }
        }

        if(i >= rtapd->conf->SsidNum)
        {
            DBGPRINT(RT_DEBUG_WARN, "Receive unexpected DA (%02x:%02x:%02x:%02x:%02x:%02x)\n",
                     MAC2STR(da));
            return;
        }

        if (ethertype == ETH_P_PRE_AUTH)
        {
            DBGPRINT(RT_DEBUG_TRACE, "Receive WPA2 pre-auth packet for %s%d\n", rtapd->prefix_wlan_name, apidx);
        }
        else
        {
            DBGPRINT(RT_DEBUG_TRACE, "Receive EAP packet for %s%d\n", rtapd->prefix_wlan_name, apidx);
        }
    }
    else
    {
        DBGPRINT(RT_DEBUG_ERROR, "Receive unexpected ethertype 0x%04X!!!\n", ethertype);
        return;
    }

    pos = rec->xframe;

    //strip 4 bytes for valn tag
    if(isVlanTag)
    {
        pos += 4;
        left -= 4;
    }

    /* Check if this is a internal command or not */
    if (left == sizeof(RalinkIe) &&
        RTMPCompareMemory(pos, RalinkIe, 5) == 0)
    {
        u8  icmd = *(pos + 5);

        switch(icmd)
        {
            case DOT1X_DISCONNECT_ENTRY:
            {
                struct sta_info *s;

                s = rtapd->sta_hash[STA_HASH(sa)];
                while (s != NULL && memcmp(s->addr, sa, 6) != 0)
                    s = s->hnext;

                DBGPRINT(RT_DEBUG_TRACE, "Receive discard-notification form wireless driver.\n");
                if (s)
                {
                    DBGPRINT(RT_DEBUG_TRACE,"This station(%02x:%02x:%02x:%02x:%02x:%02x) is removed.\n", MAC2STR(sa));
                    Ap_free_sta(rtapd, s);
                }
                else
                {
                    DBGPRINT(RT_DEBUG_INFO, "This station(%02x:%02x:%02x:%02x:%02x:%02x) doesn't exist.\n", MAC2STR(sa));
                }
            }
            break;

            case DOT1X_RELOAD_CONFIG:
                Handle_reload_config(rtapd);
                break;

            default:
                DBGPRINT(RT_DEBUG_ERROR, "Unknown internal command(%d)!!!\n", icmd);
                break;
        }
    }
    else
    {
        /* Process the general EAP packet */
        ieee802_1x_receive(rtapd, sa, &apidx, pos, left, ethertype, sock);
    }
}

int Apd_init_sockets(rtapd *rtapd)
{
    struct ifreq ifr;
    struct sockaddr_ll addr;
    int i;

    // 1. init ethernet interface socket for pre-auth
    for (i = 0; i < rtapd->conf->num_preauth_if; i++)
    {
        rtapd->eth_sock[i] = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PRE_AUTH));
        if (rtapd->eth_sock[i] < 0)
        {
            perror("socket[PF_PACKET,SOCK_RAW](eth_sock)");
            return -1;
        }

        if (eloop_register_read_sock(rtapd->eth_sock[i], Handle_read, rtapd, NULL))
        {
            DBGPRINT(RT_DEBUG_ERROR,"Could not register read socket(eth_sock)\n");
            return -1;
        }

        memset(&ifr, 0, sizeof(ifr));
        strcpy(ifr.ifr_name, rtapd->conf->preauth_if_name[i]);
        DBGPRINT(RT_DEBUG_TRACE,"Register pre-auth interface as (%s)\n", ifr.ifr_name);

        if (ioctl(rtapd->eth_sock[i], SIOCGIFINDEX, &ifr) != 0)
        {
            perror("ioctl(SIOCGIFHWADDR)(eth_sock)");
            return -1;
        }

        memset(&addr, 0, sizeof(addr));
        addr.sll_family = AF_PACKET;
        addr.sll_ifindex = ifr.ifr_ifindex;
        if (bind(rtapd->eth_sock[i], (struct sockaddr *) &addr, sizeof(addr)) < 0)
        {
            perror("bind");
            return -1;
        }
        DBGPRINT(RT_DEBUG_TRACE,"Pre-auth raw packet socket binding on %s(socknum=%d,ifindex=%d)\n",
                 ifr.ifr_name, rtapd->eth_sock[i], addr.sll_ifindex);
    }

    // 2. init wireless interface socket for EAP negotiation
    for (i = 0; i < rtapd->conf->num_eap_if; i++)
    {
        rtapd->wlan_sock[i] = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PAE));

        if (rtapd->wlan_sock[i] < 0)
        {
            perror("socket[PF_PACKET,SOCK_RAW]");
            return -1;
        }

        if (eloop_register_read_sock(rtapd->wlan_sock[i], Handle_read, rtapd, NULL))
        {
            DBGPRINT(RT_DEBUG_ERROR,"Could not register read socket\n");
            return -1;
        }

        memset(&ifr, 0, sizeof(ifr));
        strcpy(ifr.ifr_name, rtapd->conf->eap_if_name[i]);
        DBGPRINT(RT_DEBUG_TRACE,"Register EAP interface as (%s)\n", ifr.ifr_name);

        if (ioctl(rtapd->wlan_sock[i], SIOCGIFINDEX, &ifr) != 0)
        {
            perror("ioctl(SIOCGIFHWADDR)");
            return -1;
        }

        memset(&addr, 0, sizeof(addr));
        addr.sll_family = AF_PACKET;
        addr.sll_ifindex = ifr.ifr_ifindex;
        if (bind(rtapd->wlan_sock[i], (struct sockaddr *) &addr, sizeof(addr)) < 0)
        {
            perror("bind");
            return -1;
        }
        DBGPRINT(RT_DEBUG_TRACE, "EAP raw packet socket binding on %s (socknum=%d,ifindex=%d)\n",
                 ifr.ifr_name, rtapd->wlan_sock[i], addr.sll_ifindex);
    }


    // 3. Get wireless interface MAC address
    for(i = 0; i < rtapd->conf->SsidNum; i++)
    {
        int s = -1;

        s = socket(AF_INET, SOCK_DGRAM, 0);

        if (s < 0)
        {
            perror("socket[AF_INET,SOCK_DGRAM]");
            return -1;
        }

        memset(&ifr, 0, sizeof(ifr));
        sprintf(ifr.ifr_name, "%s%d",rtapd->prefix_wlan_name, i);
        //sprintf(ifr.ifr_name, "ra%d", i);

        // Get MAC address
        if (ioctl(s, SIOCGIFHWADDR, &ifr) != 0)
        {
            perror("ioctl(SIOCGIFHWADDR)");
            close(s);
            return -1;
        }

        DBGPRINT(RT_DEBUG_INFO," Device %s has ifr.ifr_hwaddr.sa_family %d\n",ifr.ifr_name, ifr.ifr_hwaddr.sa_family);
        if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER)
        {
            DBGPRINT(RT_DEBUG_ERROR,"IF-%s : Invalid HW-addr family 0x%04x\n", ifr.ifr_name, ifr.ifr_hwaddr.sa_family);
            close(s);
            return -1;
        }

        memcpy(rtapd->own_addr[i], ifr.ifr_hwaddr.sa_data, ETH_ALEN);
        DBGPRINT(RT_DEBUG_TRACE, "IF-%s MAC Address = " MACSTR "\n", ifr.ifr_name, MAC2STR(rtapd->own_addr[i]));

        close(s);
    }


    return 0;
}

static void Apd_cleanup(rtapd *rtapd)
{
    int i;

    for (i = 0; i < MAX_MBSSID_NUM; i++)
    {
        if (rtapd->wlan_sock[i] >= 0)
            close(rtapd->wlan_sock[i]);
        if (rtapd->eth_sock[i] >= 0)
            close(rtapd->eth_sock[i]);
    }
    if (rtapd->ioctl_sock >= 0)
        close(rtapd->ioctl_sock);

    Radius_client_deinit(rtapd);

    Config_free(rtapd->conf);
    rtapd->conf = NULL;

    free(rtapd->prefix_wlan_name);
}

static int Apd_setup_interface(rtapd *rtapd)
{
#if MULTIPLE_RADIUS
    int     i;
#endif

    if (Apd_init_sockets(rtapd))
        return -1;

    if (Radius_client_init(rtapd))
    {
        DBGPRINT(RT_DEBUG_ERROR,"RADIUS client initialization failed.\n");
        return -1;
    }

    if (ieee802_1x_init(rtapd))
    {
        DBGPRINT(RT_DEBUG_ERROR,"IEEE 802.1X initialization failed.\n");
        return -1;
    }
#if MULTIPLE_RADIUS
    for (i = 0; i < rtapd->conf->SsidNum; i++)
        DBGPRINT(RT_DEBUG_TRACE,"auth_serv_sock[%d] = %d\n", i, rtapd->radius->mbss_auth_serv_sock[i]);
#else
    DBGPRINT(RT_DEBUG_TRACE,"rtapd->radius->auth_serv_sock = %d\n",rtapd->radius->auth_serv_sock);
#endif

    return 0;
}

static void usage(void)
{
    DBGPRINT(RT_DEBUG_OFF, "USAGE :  	rtdot1xd [optional command]\n");
    DBGPRINT(RT_DEBUG_OFF, "[optional command] : \n");
    DBGPRINT(RT_DEBUG_OFF, "-i <card_number> : indicate which card is used\n");
    DBGPRINT(RT_DEBUG_OFF, "-d <debug_level> : set debug level\n");

    exit(1);
}

static rtapd * Apd_init(const char *prefix_name)
{
    rtapd *rtapd;
    int     i;

    rtapd = malloc(sizeof(*rtapd));
    if (rtapd == NULL)
    {
        DBGPRINT(RT_DEBUG_ERROR,"Could not allocate memory for rtapd data\n");
        goto fail;
    }
    memset(rtapd, 0, sizeof(*rtapd));

    rtapd->prefix_wlan_name = strdup(prefix_name);
    if (rtapd->prefix_wlan_name == NULL)
    {
        DBGPRINT(RT_DEBUG_ERROR,"Could not allocate memory for prefix_wlan_name\n");
        goto fail;
    }

    // init ioctl socket
    rtapd->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
    if (rtapd->ioctl_sock < 0)
    {
        DBGPRINT(RT_DEBUG_ERROR,"Could not init ioctl socket \n");
        goto fail;
    }


    rtapd->conf = Config_read(rtapd->ioctl_sock, rtapd->prefix_wlan_name);
    if (rtapd->conf == NULL)
    {
        DBGPRINT(RT_DEBUG_ERROR,"Could not allocate memory for rtapd->conf \n");
        goto fail;
    }

    for (i = 0; i < MAX_MBSSID_NUM; i++)
    {
        rtapd->wlan_sock[i] = -1;
        rtapd->eth_sock[i] = -1;
    }

    return rtapd;

fail:
    if (rtapd)
    {
        if (rtapd->conf)
            Config_free(rtapd->conf);

        if (rtapd->prefix_wlan_name)
            free(rtapd->prefix_wlan_name);

        free(rtapd);
    }
    return NULL;

}

static void Handle_usr1(int sig, void *eloop_ctx, void *signal_ctx)
{
    struct hapd_interfaces *rtapds = (struct hapd_interfaces *) eloop_ctx;
    struct rtapd_config *newconf;
    int i;

    DBGPRINT(RT_DEBUG_TRACE,"Reloading configuration\n");
    for (i = 0; i < rtapds->count; i++)
    {
        rtapd *rtapd = rtapds->rtapd[i];
        newconf = Config_read(rtapd->ioctl_sock, rtapd->prefix_wlan_name);
        if (newconf == NULL)
        {
            DBGPRINT(RT_DEBUG_ERROR,"Failed to read new configuration file - continuing with old.\n");
            continue;
        }

        /* TODO: update dynamic data based on changed configuration
         * items (e.g., open/close sockets, remove stations added to
         * deny list, etc.) */
        Radius_client_flush(rtapd);
        Config_free(rtapd->conf);
        rtapd->conf = newconf;
        Apd_free_stas(rtapd);

        /* when reStartAP, no need to reallocate sock
                for (i = 0; i < rtapd->conf->SsidNum; i++)
                {
                    if (rtapd->sock[i] >= 0)
                        close(rtapd->sock[i]);

                    rtapd->sock[i] = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
                    if (rtapd->sock[i] < 0)
                    {
                        perror("socket[PF_PACKET,SOCK_RAW]");
                        return;
                    }
                }*/

#if MULTIPLE_RADIUS
        for (i = 0; i < MAX_MBSSID_NUM; i++)
            rtapd->radius->mbss_auth_serv_sock[i] = -1;
#else
        rtapd->radius->auth_serv_sock = -1;
#endif

        if (Radius_client_init(rtapd))
        {
            DBGPRINT(RT_DEBUG_ERROR,"RADIUS client initialization failed.\n");
            return;
        }
#if MULTIPLE_RADIUS
        for (i = 0; i < rtapd->conf->SsidNum; i++)
            DBGPRINT(RT_DEBUG_TRACE, "auth_serv_sock[%d] = %d\n", i, rtapd->radius->mbss_auth_serv_sock[i]);
#else
        DBGPRINT(RT_DEBUG_TRACE,"rtapd->radius->auth_serv_sock = %d\n",rtapd->radius->auth_serv_sock);
#endif
    }
}

void Handle_term(int sig, void *eloop_ctx, void *signal_ctx)
{
    //FILE    *f;
    //char    buf[256], *pos;
    //int     line = 0, i;
    //int     filesize,cur = 0;
    //char    *ini_buffer;             /* storage area for .INI file */

    DBGPRINT(RT_DEBUG_ERROR,"Signal %d received - terminating\n", sig);

#if 0
    f = fopen(RT2860AP_SYSTEM_PATH, "r");
    if (f == NULL)
    {
        DBGPRINT(RT_DEBUG_ERROR,"Could not open configuration file '%s' for reading.\n", RT2860AP_SYSTEM_PATH);
        return;
    }

    if ((fseek(f, 0, SEEK_END))!=0)
        return;
    filesize=ftell(f);
    DBGPRINT(RT_DEBUG_ERROR,"filesize %d   - terminating\n", filesize);

    if ((ini_buffer=(char *)malloc(filesize + 1 ))==NULL)
        return;   //out of memory
    fseek(f,0,SEEK_SET);
    fread(ini_buffer, filesize, 1, f);
    fseek(f,0,SEEK_SET);
    ini_buffer[filesize]='\0';

    while ((fgets(buf, sizeof(buf), f)))
    {
        line++;
        if (buf[0] == '#')
            continue;
        pos = buf;
        while (*pos != '\0')
        {
            if (*pos == '\n')
            {
                *pos = '\0';
                break;
            }
            pos++;
        }
        if (buf[0] == '\0')
            continue;

        pos = strchr(buf, '=');
        if (pos == NULL)
        {
            pos = strchr(buf, '[');
            continue;
        }
        *pos = '\0';
        pos++;

        if ((strcmp(buf, "pid") == 0) )
        {
            cur = 0;
            while(cur < (int)filesize)
            {
                if ((ini_buffer[cur]=='p') && (ini_buffer[cur+1]=='i') && (ini_buffer[cur+2]=='d'))
                {
                    cur += 4;
                    for( i=4; i>=0; i--)
                    {
                        if (ini_buffer[cur] !='\n' )
                        {
                            ini_buffer[cur] =0x30;
                        }
                        else
                        {
                            break;
                        }
                        cur++;
                    }
                    break;
                }
                cur++;
            }
        }
    }
    fseek(f,0,SEEK_SET);
    fprintf(f, "%s", ini_buffer);
    fclose(f);
#endif

    eloop_terminate();
}


int main(int argc, char *argv[])
{
    struct hapd_interfaces interfaces;
    pid_t child_pid;
    int ret = 1, i;
    int c;
    pid_t auth_pid;
    char prefix_name[IFNAMSIZ+1];

    printf("program name = '%s'\n", argv[0]);

    if (strstr(argv[0], "8021xdi"))
    {
        printf("1program name = '%s'\n", argv[0]);
        strcpy(prefix_name, "rai");
    }
    else
    {
        printf("2program name = '%s'\n", argv[0]);
        strcpy(prefix_name, "ra");
    }

    for (;;)
    {
        c = getopt(argc, argv, "d:i:h");
        if (c < 0)
            break;

        switch (c)
        {
            case 'd':
                /*  set Debug level -
                        RT_DEBUG_OFF        0
                        RT_DEBUG_ERROR      1
                        RT_DEBUG_WARN       2
                        RT_DEBUG_TRACE      3
                        RT_DEBUG_INFO       4
                */
                printf("Set debug level as %s\n", optarg);
                RTDebugLevel = (int)strtol(optarg, 0, 10);
                break;
#if 1 /* FIXME: original prefix name seems wrong. */
            case 'i':
                // Assign the wireless interface when support multiple cards
                sprintf(prefix_name, "%s", optarg);
                break;
#else
            case 'i':
                // Assign the wireless interface when support multiple cards
                sprintf(prefix_name, "%s%02d_", prefix_name, ((int)strtol(optarg, 0, 10) - 1));
                break;
#endif
            case 'h':
            default:
                usage();
                break;
        }
    }

    printf("Ralink DOT1X daemon, version = '%s' \n", dot1x_version);
    DBGPRINT(RT_DEBUG_TRACE, "prefix_name = '%s'\n", prefix_name);


    child_pid = fork();
    if (child_pid == 0)
    {
        auth_pid = getpid();
        DBGPRINT(RT_DEBUG_TRACE, "Porcess ID = %d\n",auth_pid);

        openlog("rtdot1xd",0,LOG_DAEMON);
        // set number of configuration file 1
        interfaces.count = 1;
        interfaces.rtapd = malloc(sizeof(rtapd *));
        if (interfaces.rtapd == NULL)
        {
            DBGPRINT(RT_DEBUG_ERROR,"malloc failed\n");
            exit(1);
        }

        eloop_init(&interfaces);
        eloop_register_signal(SIGINT, Handle_term, NULL);
        eloop_register_signal(SIGTERM, Handle_term, NULL);
        eloop_register_signal(SIGUSR1, Handle_usr1, NULL);
        eloop_register_signal(SIGHUP, Handle_usr1, NULL);

        interfaces.rtapd[0] = Apd_init(prefix_name);
        if (!interfaces.rtapd[0])
            goto out;
        if (Apd_setup_interface(interfaces.rtapd[0]))
            goto out;

        // Notify driver about PID
        RT_ioctl(interfaces.rtapd[0]->ioctl_sock, RT_PRIV_IOCTL, (char *)&auth_pid, sizeof(int), prefix_name, 0, RT_SET_APD_PID | OID_GET_SET_TOGGLE);

        eloop_run();

        Apd_free_stas(interfaces.rtapd[0]);
        ret = 0;

    out:
        for (i = 0; i < interfaces.count; i++)
        {
            if (!interfaces.rtapd[i])
                continue;

            Apd_cleanup(interfaces.rtapd[i]);
            free(interfaces.rtapd[i]);
        }

        free(interfaces.rtapd);
        eloop_destroy();
        closelog();
        return ret;
    }
    else
        return 0;
}

